package cn.mw.cmdb.link.service;

import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.link.constant.MwNetWorkLinkConstant;
import cn.mw.cmdb.link.entity.LinkLabelDto;
import cn.mw.cmdb.link.entity.MwLinkTreeDto;
import cn.mw.cmdb.link.entity.MwNetWorkLinkDto;
import cn.mw.cmdb.link.entity.MwNetWorkLinkImportDto;
import cn.mw.cmdb.link.enums.LinkDetectionWayEnum;
import cn.mw.cmdb.link.enums.LinkFetchPortEnum;
import cn.mw.cmdb.link.service.impl.MwNetWorkLinkServiceImpl;
import cn.mw.cmdb.mongoMapper.MwLinkTreeMapper;
import cn.mw.cmdb.param.ModelPropertyParam;
import cn.mw.cmdb.param.PropertySearchParam;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.service.impl.ModelPropertyServiceImpl;
import cn.mw.components.mongodb.exception.BusinessException;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.microMonitorCommon.api.common.MwTPServerService;
import cn.mw.microMonitorCommon.api.user.MwUserApi;
import cn.mw.microMonitorCommon.entity.common.MwTPServerTable;
import cn.mw.microMonitorCommon.entity.userDTO.GroupDTO;
import cn.mw.microMonitorCommon.entity.userDTO.OrgDTO;
import cn.mw.microMonitorCommon.security.dto.MwUser;
import cn.mw.microMonitorCommon.util.ListMapObjUtils;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

import static cn.mw.cmdb.entity.PropertyTypeEnumSingle.enumInfoListKey;
import static cn.mw.cmdb.processor.MonitorValue.MonitorServerIdKey;
import static cn.mw.cmdb.processor.MonitorValue.MonitorTypeIdKey;

/**
 * @description 线路导入管理
 */
@Component
@Slf4j
public class LinkImportManager {

    @DubboReference(check = false, timeout = 12000, mock = "true")
    public MwTPServerService tpServerService;

    @DubboReference(check = false, timeout = 12000, mock = "true")
    public MwUserApi userApi;

    private MessageSource messageSource;

    private final String enable = "是";
    private final String enable_not = "否";
    private final String ORG = "ORG_KEY";
    private final String GROUP = "GROUP_KEY";
    private final String PRINCIPAL = "PRINCIPAL_KEY";
    private final String SHEET_NAME = "线路导入";
    private final String LINK_MODEL_ID = "158062698662199296";
    private final String ICMP_MODEL_ID = "97211217252188160";

    public LinkImportManager(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    public void importData(MultipartFile file, CmdbServiceManage cmdbServiceManage, MwLinkTreeMapper linkTreeMapper, MwNetWorkLinkServiceImpl workLinkService, HttpServletResponse response) throws Exception {
        List<MwNetWorkLinkImportDto> errorDtos = new ArrayList<>();
        List<MwNetWorkLinkDto> netWorkLinkDtos = new ArrayList<>();
        InputStream inputStream = file.getInputStream();
        Workbook workbook = null;
        String fileName = file.getOriginalFilename();
        if (fileName.endsWith(".xls")) {
            workbook = new HSSFWorkbook(inputStream);
        }
        if (fileName.endsWith(".xlsx")) {
            workbook = new XSSFWorkbook(inputStream);
        }
        if (workbook == null) {
            return;
        }
        List<MwNetWorkLinkImportDto> linkImportDtos = readExcelData(workbook,cmdbServiceManage);
        if (CollectionUtils.isEmpty(linkImportDtos)) {
            return;
        }
        List<MwNetWorkLinkImportDto> newImportDtoList = new ArrayList<>(linkImportDtos);
        handlerAssetsInfo(linkImportDtos, cmdbServiceManage);
        handlerIcmpLink(linkImportDtos,cmdbServiceManage);
        Map<String, String> linkTreeMap = getLinkTreeInfo(linkImportDtos, linkTreeMapper);
        netWorkLinkDtos = handlerMappingValue(linkImportDtos, linkTreeMap);
        if(CollectionUtils.isNotEmpty(netWorkLinkDtos)){
            for (MwNetWorkLinkDto netWorkLinkDto : netWorkLinkDtos) {
                try {
                    workLinkService.saveLink(netWorkLinkDto);
                }catch (BusinessException e){
                    log.error("导入线路信息出错",e);
                    List<MwNetWorkLinkImportDto> dtoList = importDataErrorMatch(netWorkLinkDto, newImportDtoList);
                    if(CollectionUtils.isNotEmpty(dtoList)){
                        for (MwNetWorkLinkImportDto linkImportDto : dtoList) {
                            linkImportDto.setImportResult("失败");
                            String message = messageSource.getMessage(e.getMessageKey(), null, LocaleContextHolder.getLocale());
                            linkImportDto.setErrorMessage("添加线路信息出错>>>"+message);
                        }
                    }
                    errorDtos.addAll(dtoList);
                }
            }
        }
        if(CollectionUtils.isNotEmpty(errorDtos)){
            //导出导入失败的数据
            exportData(response,linkTreeMapper,cmdbServiceManage,errorDtos,true);
        }
    }


    public void exportTemplate(HttpServletResponse response,MwLinkTreeMapper linkTreeMapper,CmdbServiceManage cmdbServiceManage) throws Exception {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet(SHEET_NAME);
        XSSFCellStyle headStyle = setHeadStyle(workbook);
        Row headerRow = sheet.createRow(0);
        //获取表头数据
        List<String> headInfo = getExportHeadInfo(cmdbServiceManage,100);
        for (int i = 0; i < headInfo.size(); i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headInfo.get(i));
            sheet.setColumnWidth(i, 6000);
            cell.setCellStyle(headStyle);
            linkGroupDropDown(linkTreeMapper,i,sheet,headInfo.get(i));
            takeValuePortDropDown(i,sheet,headInfo.get(i));
            enableDetectionDropDown(i,sheet,headInfo.get(i));
            detectionWayDropDown(i,sheet,headInfo.get(i));
        }
        Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        String fileName = milliSecond + ".xlsx";
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        OutputStream outputStream = response.getOutputStream();
        workbook.write(outputStream);
        workbook.close();
        outputStream.close();
    }


    public void exportLinkInfo(List data,HttpServletResponse response,CmdbServiceManage cmdbServiceManage,MwLinkTreeMapper linkTreeMapper) throws Exception {
        //数据转为到处实体
        List<MwNetWorkLinkImportDto> dtoList = ListMapObjUtils.castMapToBean(data, MwNetWorkLinkImportDto.class);
        //数据转换
        //查询资产
        Set<String> assetsIds = new HashSet<>();
        assetsIds.addAll(dtoList.stream().filter(item -> StringUtils.isNotEmpty(item.getSourceDeviceAsset())).map(s -> s.getSourceDeviceAsset()).collect(Collectors.toSet()));
        assetsIds.addAll(dtoList.stream().filter(item -> StringUtils.isNotEmpty(item.getTargetDeviceAsset())).map(s -> s.getTargetDeviceAsset()).collect(Collectors.toSet()));
        Map<String, InstanceInfo> assetsInfo = assetsInfo(assetsIds, null, cmdbServiceManage);
        //获取目录
        List<MwLinkTreeDto> linkTreeDtos = linkTreeMapper.findAll();
        Map<String, String> linkTreeMap = linkTreeDtos.stream().collect(Collectors.toMap(s -> s.getId(), s -> s.getLinkTreeName()));
        //获取机构
        getPermissionInfo(data,dtoList);
        //获取监控服务器
        List<Integer> serverIds = dtoList.stream().filter(item -> StringUtils.isNotEmpty(item.getMonitorServer())).map(s -> Integer.parseInt(s.getMonitorServer())).collect(Collectors.toList());
        List<MwTPServerTable> mwTPServerByServiceIds = tpServerService.getMwTPServerByServiceIds(serverIds);
        Map<Integer, String> tpServerMap = mwTPServerByServiceIds.stream().collect(Collectors.toMap(s -> s.getId(), s -> s.getMonitoringServerName()));
        for (MwNetWorkLinkImportDto linkImportDto : dtoList) {
            String sourceDeviceAsset = linkImportDto.getSourceDeviceAsset();
            if(StringUtils.isNotEmpty(sourceDeviceAsset)){
                InstanceInfo instanceInfo = assetsInfo.get(sourceDeviceAsset);
                if(instanceInfo != null){
                    linkImportDto.setSourceDeviceAsset(instanceInfo.getInstanceName());
                }
            }
            String targetDeviceAsset = linkImportDto.getTargetDeviceAsset();
            if(StringUtils.isNotEmpty(targetDeviceAsset)){
                InstanceInfo instanceInfo = assetsInfo.get(targetDeviceAsset);
                if(instanceInfo != null){
                    linkImportDto.setTargetDeviceAsset(instanceInfo.getInstanceName());
                }
            }
            String linkGroup = linkImportDto.getLinkGroup();
            if(StringUtils.isNotEmpty(linkGroup)){
                linkImportDto.setLinkGroup(linkTreeMap.get(linkGroup));
            }
            String takeValuePort = linkImportDto.getTakeValuePort();
            if(StringUtils.isNotEmpty(takeValuePort)){
                linkImportDto.setTakeValuePort(LinkFetchPortEnum.getLinkFetchPortEnum(takeValuePort).getDesc());
            }
            String monitorServer = linkImportDto.getMonitorServer();
            if(StringUtils.isNotEmpty(monitorServer)){
                linkImportDto.setMonitorServer(tpServerMap.get(Integer.parseInt(monitorServer)));
            }
            String enableDetection = linkImportDto.getEnableDetection();
            if(StringUtils.isNotEmpty(enableDetection)){
                if(Boolean.parseBoolean(enableDetection)){
                    linkImportDto.setEnableDetection(enable);
                }else{
                    linkImportDto.setEnableDetection(enable_not);
                }
            }
            String detectionWay = linkImportDto.getDetectionWay();
            if(StringUtils.isNotEmpty(detectionWay) && detectionWay.equals(LinkDetectionWayEnum.NOT_HAVE.getType())){
                linkImportDto.setDetectionWay(null);
            }
        }
        exportData(response,linkTreeMapper,cmdbServiceManage,dtoList,false);
    }


    private void getPermissionInfo(List data,List<MwNetWorkLinkImportDto> importDtos) throws Exception {
        Set<Long> orgIds = new HashSet<>();
        Set<Long> userIds = new HashSet<>();
        Set<Long> groupIds = new HashSet<>();
        Map<String,MwNetWorkLinkDto> linkMap = new HashMap<>();
        List<MwNetWorkLinkDto> dtoList = JSONArray.parseArray(JSONObject.toJSONString(data), MwNetWorkLinkDto.class);
        for (MwNetWorkLinkDto netWorkLinkDto : dtoList) {
            linkMap.put(netWorkLinkDto.getLinkId(),netWorkLinkDto);
            List<List<Long>> orgs = netWorkLinkDto.getOrgs();
            if(CollectionUtils.isNotEmpty(orgs)){
                for (List<Long> org : orgs) {
                    orgIds.addAll(org);
                }
            }
            List<Long> users = netWorkLinkDto.getUsers();
            if(CollectionUtils.isNotEmpty(orgs)){
                userIds.addAll(users);
            }
            List<Long> groups = netWorkLinkDto.getGroups();
            if(CollectionUtils.isNotEmpty(groups)){
                groupIds.addAll(groups);
            }
        }
        Map<Long,String> orgMap = new HashMap<>();
        Map<Long,String> userMap = new HashMap<>();
        Map<Long,String> groupMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(orgIds)){
            List<OrgDTO> orgDTOs = userApi.getOrgListByOrgIds(new ArrayList<>(orgIds));
            if(CollectionUtils.isNotEmpty(orgDTOs)){
                orgMap = orgDTOs.stream().collect(Collectors.toMap(s->s.getId(),s->s.getOrgName()));
            }
        }
        if(CollectionUtils.isNotEmpty(userIds)){
            List<MwUser> users = userApi.getUsersByUserIds(new ArrayList<>(userIds));
            if(CollectionUtils.isNotEmpty(users)){
                userMap = users.stream().collect(Collectors.toMap(s->s.getId(),s->s.getNickName()));
            }
        }
        if(CollectionUtils.isNotEmpty(groupIds)){
            List<GroupDTO> groupDTOS = userApi.getGroupListByIds(new ArrayList<>(groupIds));
            if(CollectionUtils.isNotEmpty(groupDTOS)){
                groupMap = groupDTOS.stream().collect(Collectors.toMap(s->s.getId(),s->s.getGroupName()));
            }
        }
        for (MwNetWorkLinkImportDto importDto : importDtos) {
            MwNetWorkLinkDto netWorkLinkDto = linkMap.get(importDto.getLinkId());
            if(netWorkLinkDto == null){
                continue;
            }
            importDto.setOrg(getOrgName(netWorkLinkDto.getOrgs(),orgMap));
            importDto.setPrincipal(getUserName(netWorkLinkDto.getUsers(),userMap));
            importDto.setGroup(getGroupName(netWorkLinkDto.getGroups(),groupMap));
        }
    }


    private Map<String, InstanceInfo> assetsInfo(Set<String> assetsIds,Set<String> assetsNames,CmdbServiceManage cmdbServiceManage) throws Exception {
        Query query = new Query();
        if(CollectionUtils.isNotEmpty(assetsNames)){
            query.addCriteria(CriteriaWrapper.where(InstanceInfo::getInstanceName).in(new ArrayList<>(assetsNames)));
        }
        if(CollectionUtils.isNotEmpty(assetsIds)){
            query.addCriteria(CriteriaWrapper.where(InstanceInfo::getId).in(new ArrayList<>(assetsIds)));
        }
        InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        List<InstanceInfo> instanceInfoList = instanceService.doListByQueryNotAuth(query);
        Map<String, InstanceInfo> assetsMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(assetsNames)){
            assetsMap = instanceInfoList.stream().collect(Collectors.toMap(s -> s.getInstanceName(), s->s, (oldValue, newValue) -> newValue));
        }
        if(CollectionUtils.isNotEmpty(assetsIds)){
            assetsMap = instanceInfoList.stream().collect(Collectors.toMap(s -> s.getId(), s->s, (oldValue, newValue) -> newValue));
        }
        return assetsMap;
    }

    private void handlerIcmpLink(List<MwNetWorkLinkImportDto> linkImportDtos,CmdbServiceManage cmdbServiceManage) throws Exception {
        List<MwNetWorkLinkImportDto> icmpLinks = linkImportDtos.stream().filter(item -> item.getDetectionWay() != null && item.getDetectionWay().equals(LinkDetectionWayEnum.ICMP.getType())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(icmpLinks)){
            return;
        }
        Set<String> ipAddress = icmpLinks.stream().map(s -> s.getDetectionTargetIp()).collect(Collectors.toSet());
        InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        Query query = new Query();
        query.addCriteria(CriteriaWrapper.where(InstanceInfo::getInBandIp).in(new ArrayList<>(ipAddress)));
        query.addCriteria(CriteriaWrapper.where(InstanceInfo::getModelId).is(ICMP_MODEL_ID));
        List<InstanceInfo> instanceInfos = instanceService.doListByQueryNotAuth(query);
        if(CollectionUtils.isEmpty(instanceInfos)){
            return;
        }
        Map<String, InstanceInfo> infoMap = instanceInfos.stream().collect(Collectors.toMap(s -> s.getInBandIp(), s -> s,(oldValue, newValue) -> newValue));
        for (MwNetWorkLinkImportDto icmpLink : icmpLinks) {
            InstanceInfo instanceInfo = infoMap.get(icmpLink.getDetectionTargetIp());
            if(instanceInfo == null){
                continue;
            }
            icmpLink.setDetectionTargetIpId(instanceInfo.getId());
        }
    }

    private List<ModelPropertyParam> getLinkModelInfo(CmdbServiceManage cmdbServiceManage) throws Exception {
        ModelPropertyServiceImpl propertyService = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
        PropertySearchParam propertySearchParam = new PropertySearchParam();
        propertySearchParam.setModelId(LINK_MODEL_ID);
        List<ModelPropertyParam> modelPropertyParams = propertyService.doSelectList(propertySearchParam);
        return modelPropertyParams;
    }

    private void linkGroupDropDown(MwLinkTreeMapper linkTreeMapper,Integer col,Sheet sheet,String name){
        if(StringUtils.isEmpty(name) || !name.contains(MwNetWorkLinkConstant.LINK_GROUP)){
            return;
        }
        List<MwLinkTreeDto> linkTreeDtos = linkTreeMapper.findAll();
        List<String> dropDownValues = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(linkTreeDtos)){
            dropDownValues = linkTreeDtos.stream().map(s -> s.getLinkTreeName()).collect(Collectors.toList());
        }
        createDropDownFormat(col,sheet,dropDownValues);
    }


    private void takeValuePortDropDown(Integer col,Sheet sheet,String name){
        if(StringUtils.isEmpty(name) || !name.contains(MwNetWorkLinkConstant.FETCH_PORT)){
            return;
        }
        List<String> dropDownValues = new ArrayList<>();
        for (LinkFetchPortEnum value : LinkFetchPortEnum.values()) {
            dropDownValues.add(value.getDesc());
        }
        createDropDownFormat(col,sheet,dropDownValues);
    }

    private void detectionWayDropDown(Integer col,Sheet sheet,String name){
        if(StringUtils.isEmpty(name) || !name.contains(MwNetWorkLinkConstant.DETECTION_WAY)){
            return;
        }
        List<String> dropDownValues = new ArrayList<>();
        for (LinkDetectionWayEnum value : LinkDetectionWayEnum.values()) {
            dropDownValues.add(value.getType());
        }
        createDropDownFormat(col,sheet,dropDownValues);
    }

    private void enableDetectionDropDown(Integer col,Sheet sheet,String name){
        if(StringUtils.isEmpty(name) || !name.contains(MwNetWorkLinkConstant.FIRING_DETECTION)){
            return;
        }
        List<String> dropDownValues = new ArrayList<>();
        for (LinkFetchPortEnum value : LinkFetchPortEnum.values()) {
            dropDownValues.add(value.getDesc());
        }
        createDropDownFormat(col,sheet,Arrays.asList(enable,enable_not));
    }


    private void createDropDownFormat(Integer col,Sheet sheet,List<String> dropDownValues){
        CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 1000, col, col);
        // 获取数据验证辅助类
        DataValidationHelper validationHelper = sheet.getDataValidationHelper();
        DataValidationConstraint constraint = validationHelper.createExplicitListConstraint(dropDownValues.toArray(new String[0]));
        DataValidation dataValidation = validationHelper.createValidation(constraint, cellRangeAddressList);
        // 防止输入不在列表中的数据
        dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
        dataValidation.setShowErrorBox(true);
        // 将验证添加到工作表
        sheet.addValidationData(dataValidation);
    }

    private XSSFCellStyle setHeadStyle(Workbook workbook){
        //表头样式
        XSSFCellStyle headStyle = (XSSFCellStyle) workbook.createCellStyle();
        XSSFFont headFont = (XSSFFont) workbook.createFont();
        headFont.setFontHeightInPoints((short) 11);
        headFont.setBold(true);
        headStyle.setFillBackgroundColor((short) 45333);
        headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        headStyle.setBorderRight(BorderStyle.THIN);
        headStyle.setBorderLeft(BorderStyle.THIN);
        headStyle.setBorderBottom(BorderStyle.THIN);
        headStyle.setBorderTop(BorderStyle.THIN);
        headStyle.setAlignment(HorizontalAlignment.CENTER); //水平居中
        headStyle.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中
        headStyle.setWrapText(true); //自动换行
        headStyle.setFont(headFont);
        return headStyle;
    }

    private List<String> getExportHeadInfo(CmdbServiceManage cmdbServiceManage,int number) throws Exception {
        List<String> heads = new ArrayList<>();
        TreeMap<Integer, String> fieldMap = new TreeMap<>();
        Field[] fields = MwNetWorkLinkImportDto.class.getDeclaredFields();
        for (Field field : fields) {
            if (!field.isAnnotationPresent(ExcelProperty.class)) {
                continue;
            }
            ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
            String annotationValue = fieldAnnotation.value()[0];
            Integer order = fieldAnnotation.order();
            if (StringUtils.isEmpty(annotationValue) || order == null || order > number) {
                continue;
            }
            fieldMap.put(order, annotationValue);
        }
        for (Map.Entry<Integer, String> entry : fieldMap.entrySet()) {
            heads.add(entry.getValue());
        }
        //获取线路模型的字段信息
        List<ModelPropertyParam> linkModelInfo = getLinkModelInfo(cmdbServiceManage);
        if(CollectionUtils.isNotEmpty(linkModelInfo)){
            for (ModelPropertyParam modelPropertyParam : linkModelInfo) {
                heads.add(modelPropertyParam.getName());
            }
        }
        return heads;
    }

    private List<MwNetWorkLinkDto> handlerMappingValue(List<MwNetWorkLinkImportDto> linkImportDtos, Map<String, String> linkTreeMap) throws Exception {
        List<MwNetWorkLinkDto> netWorkLinkDtos = new ArrayList<>();
        Map<String, Integer> tpServerMap = getTpServer(linkImportDtos);
        //机构，用户，用户组信息
        Map<String, Object> authMap = getAuthInfo(linkImportDtos);
        for (MwNetWorkLinkImportDto linkImportDto : linkImportDtos) {
            MwNetWorkLinkDto netWorkLinkDto = new MwNetWorkLinkDto();
            String takeValuePort = linkImportDto.getTakeValuePort();
            if (StringUtils.isNotEmpty(takeValuePort)) {
                String type = LinkFetchPortEnum.getLinkFetchPortType(takeValuePort);
                linkImportDto.setTakeValuePort(type);
            }
            String linkGroup = linkImportDto.getLinkGroup();
            if (StringUtils.isNotEmpty(linkGroup)) {
                linkImportDto.setLinkGroup(linkTreeMap.get(linkGroup));
            }
            BeanUtils.copyProperties(linkImportDto, netWorkLinkDto);
            String enableDetection = linkImportDto.getEnableDetection();
            if (StringUtils.isNotEmpty(enableDetection) && enableDetection.equals(enable)) {
                netWorkLinkDto.setEnableDetection(true);
            } else {
                netWorkLinkDto.setEnableDetection(false);
                netWorkLinkDto.setDetectionWay(LinkDetectionWayEnum.NOT_HAVE.getType());
            }
            String monitorServer = linkImportDto.getMonitorServer();
            if (StringUtils.isNotEmpty(monitorServer)) {
                netWorkLinkDto.setMonitorServerId(tpServerMap.get(monitorServer));
            }
            setOrgInfo(linkImportDto.getOrg(), netWorkLinkDto, authMap);
            setPrincipalInfo(linkImportDto.getPrincipal(), netWorkLinkDto, authMap);
            setGroupInfo(linkImportDto.getGroup(), netWorkLinkDto, authMap);
            netWorkLinkDtos.add(netWorkLinkDto);
        }
        return netWorkLinkDtos;
    }

    private void setGroupInfo(String groupName, MwNetWorkLinkDto netWorkLinkDto, Map<String, Object> authMap) {
        if (StringUtils.isEmpty(groupName) || !authMap.containsKey(GROUP)) {
            return;
        }
        List<GroupDTO> groups = (List<GroupDTO>) authMap.get(GROUP);
        Map<String, Long> nameByIdMap = groups.stream().collect(Collectors.toMap(s -> s.getGroupName(), s -> s.getId(), (o1, o2) -> o1));
        List<Long> groupIdList = new ArrayList<>();
        String[] split = groupName.split(",");
        for (String name : split) {
            if (!nameByIdMap.containsKey(name)) {
                continue;
            }
            Long groupId = nameByIdMap.get(name);
            groupIdList.add(groupId);
        }
        netWorkLinkDto.setGroups(groupIdList);
    }

    private void setPrincipalInfo(String principalName, MwNetWorkLinkDto netWorkLinkDto, Map<String, Object> authMap) {
        if (StringUtils.isEmpty(principalName) || !authMap.containsKey(PRINCIPAL)) {
            return;
        }
        List<MwUser> users = (List<MwUser>) authMap.get(PRINCIPAL);
        PropertyTypeUser propertyTypeUser = new PropertyTypeUser();
        List<Long> userIds = new ArrayList<>();
        String[] split = principalName.split(",");
        for (String name : split) {
            List<Long> userIdList = new ArrayList<>();
            propertyTypeUser.setUserIds(users, name, userIdList);
            userIds.addAll(userIdList);
        }
        netWorkLinkDto.setUsers(userIds);
    }

    private void setOrgInfo(String org, MwNetWorkLinkDto netWorkLinkDto, Map<String, Object> authMap) {
        if (StringUtils.isEmpty(org) || !authMap.containsKey(ORG)) {
            return;
        }
        List<OrgDTO> orgs = (List<OrgDTO>) authMap.get(ORG);
        PropertyTypeOrg propertyTypeOrg = new PropertyTypeOrg();
        List<List<Long>> orgIds = new ArrayList<>();
        String[] split = org.split(",");
        for (String name : split) {
            List<List<Long>> idsList = new ArrayList<>();
            propertyTypeOrg.setOrgIds(orgs, idsList, name);
            orgIds.addAll(idsList);
        }
        netWorkLinkDto.setOrgs(orgIds);
    }

    private Map<String, Object> getAuthInfo(List<MwNetWorkLinkImportDto> linkImportDtos) {
        Map<String, Object> authMap = new HashMap<>();
        Set<String> orgNames = new HashSet<>();
        Set<String> groupNames = new HashSet<>();
        Set<String> principalNames = new HashSet<>();
        for (MwNetWorkLinkImportDto linkImportDto : linkImportDtos) {
            if (StringUtils.isNotEmpty(linkImportDto.getOrg())) {
                List<String> orgs = Arrays.asList(linkImportDto.getOrg().split(","));
                for (String org : orgs) {
                    orgNames.addAll(Arrays.asList(org.split("/")));
                }
            }
            if (StringUtils.isNotEmpty(linkImportDto.getPrincipal())) {
                principalNames.addAll(Arrays.asList(linkImportDto.getPrincipal().split(",")));
            }
            if (StringUtils.isNotEmpty(linkImportDto.getGroup())) {
                groupNames.addAll(Arrays.asList(linkImportDto.getGroup().split(",")));
            }
        }
        if (CollectionUtils.isNotEmpty(orgNames)) {
            List<OrgDTO> orgs = userApi.getOrgsByOrgNames(new ArrayList<>(orgNames));
            authMap.put(ORG, orgs);
        }
        if (CollectionUtils.isNotEmpty(principalNames)) {
            List<MwUser> users = userApi.getUsersByNicknames(new ArrayList<>(principalNames));
            authMap.put(PRINCIPAL, users);
        }
        if (CollectionUtils.isNotEmpty(groupNames)) {
            List<GroupDTO> groups = userApi.getGroupsByGroupNames(new ArrayList<>(groupNames));
            authMap.put(GROUP, groups);
        }
        return authMap;
    }

    private Map<String, Integer> getTpServer(List<MwNetWorkLinkImportDto> linkImportDtos) {
        Map<String, Integer> serverMap = new HashMap<>();
        Set<String> serverNames = linkImportDtos.stream().filter(item -> StringUtils.isNotEmpty(item.getMonitorServer())).map(s -> s.getMonitorServer()).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(serverNames)) {
            return serverMap;
        }
        List<MwTPServerTable> tpServerTables = tpServerService.getMwTPServerByServerNames(new ArrayList<>(serverNames));
        if (CollectionUtils.isEmpty(tpServerTables)) {
            return serverMap;
        }
        serverMap = tpServerTables.stream().collect(Collectors.toMap(s -> s.getMonitoringServerName(), s -> s.getId(), (oldValue, newValue) -> newValue));
        return serverMap;
    }

    private Map<String, String> getLinkTreeInfo(List<MwNetWorkLinkImportDto> linkImportDtos, MwLinkTreeMapper linkTreeMapper) throws Exception {
        Map<String, String> linkTreeMap = new HashMap<>();
        Set<String> linkTreeNames = linkImportDtos.stream().filter(item -> StringUtils.isNotEmpty(item.getLinkGroup())).map(s -> s.getLinkGroup()).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(linkTreeNames)) {
            return linkTreeMap;
        }
        Query query = new Query();
        query.addCriteria(CriteriaWrapper.where(MwLinkTreeDto::getLinkTreeName).in(new ArrayList<>(linkTreeNames)));
        List<MwLinkTreeDto> linkTreeDtos = linkTreeMapper.find(query);
        if (CollectionUtils.isEmpty(linkTreeDtos)) {
            return linkTreeMap;
        }
        linkTreeMap = linkTreeDtos.stream().collect(Collectors.toMap(s -> s.getLinkTreeName(), s -> s.getId(), (oldValue, newValue) -> newValue));
        return linkTreeMap;
    }

    private void handlerAssetsInfo(List<MwNetWorkLinkImportDto> linkImportDtos, CmdbServiceManage cmdbServiceManage) throws Exception {
        Set<String> assetsNames = new HashSet<>();
        //查询资产
        assetsNames.addAll(linkImportDtos.stream().filter(item -> StringUtils.isNotEmpty(item.getSourceDeviceAsset())).map(s -> s.getSourceDeviceAsset()).collect(Collectors.toSet()));
        assetsNames.addAll(linkImportDtos.stream().filter(item -> StringUtils.isNotEmpty(item.getTargetDeviceAsset())).map(s -> s.getTargetDeviceAsset()).collect(Collectors.toSet()));
        Query query = new Query(CriteriaWrapper.where(InstanceInfo::getInstanceName).in(new ArrayList<>(assetsNames)));
        InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        List<InstanceInfo> instanceInfoList = instanceService.doListByQueryNotAuth(query);
        if (CollectionUtils.isEmpty(instanceInfoList)) {
            return;
        }
        Map<String, InstanceInfo> assetsMap = instanceInfoList.stream().collect(Collectors.toMap(s -> s.getInstanceName(), s->s, (oldValue, newValue) -> newValue));
        for (MwNetWorkLinkImportDto linkImportDto : linkImportDtos) {
            String sourceDeviceAsset = linkImportDto.getSourceDeviceAsset();
            if (StringUtils.isNotEmpty(sourceDeviceAsset)) {
                InstanceInfo instanceInfo = assetsMap.get(sourceDeviceAsset);
                if(instanceInfo != null){
                    linkImportDto.setSourceDeviceAsset(instanceInfo.getId());
                    Map<String, Object> infoData = instanceInfo.getData();
                    if(infoData != null && infoData.containsKey(MonitorTypeIdKey) && infoData.containsKey(MonitorServerIdKey)){
                        linkImportDto.setSourceDeviceHostId(String.valueOf(infoData.get(MonitorTypeIdKey)));
                        linkImportDto.setSourceDeviceServerId(Integer.parseInt(String.valueOf(infoData.get(MonitorServerIdKey))));
                    }
                }
            }
            String targetDeviceAsset = linkImportDto.getTargetDeviceAsset();
            if (StringUtils.isNotEmpty(targetDeviceAsset)) {
                InstanceInfo instanceInfo = assetsMap.get(targetDeviceAsset);
                if(instanceInfo != null){
                    linkImportDto.setTargetDeviceAsset(instanceInfo.getId());
                    Map<String, Object> infoData = instanceInfo.getData();
                    if(infoData != null && infoData.containsKey(MonitorTypeIdKey) && infoData.containsKey(MonitorServerIdKey)){
                        linkImportDto.setTargetDeviceHostId(String.valueOf(infoData.get(MonitorTypeIdKey)));
                        linkImportDto.setTargetDeviceServerId(Integer.parseInt(String.valueOf(infoData.get(MonitorServerIdKey))));
                    }
                }
            }
        }
    }

    private List<MwNetWorkLinkImportDto> readExcelData(Workbook workbook,CmdbServiceManage cmdbServiceManage) throws Exception {
        List<MwNetWorkLinkImportDto> linkImportDtos = new ArrayList<>();
        Sheet sheet = workbook.getSheetAt(0);
        Row headRow = sheet.getRow(0);
        Map<Integer, String> headerMap = new HashMap<>();
        for (Cell cell : headRow) {
            headerMap.put(cell.getColumnIndex(), cell.getStringCellValue());
        }
        List<ModelPropertyParam> linkModelInfo = getLinkModelInfo(cmdbServiceManage);
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            MwNetWorkLinkImportDto linkImportDto = new MwNetWorkLinkImportDto();
            Row dataRow = sheet.getRow(i);
            if (dataRow == null) {
                continue;
            }
            List<LinkLabelDto> associationData = new ArrayList<>();
            for (Cell dataCell : dataRow) {
                String headValue = headerMap.get(dataCell.getColumnIndex());
                if (StringUtils.isNotEmpty(headValue)) {
                    Object cellValue = getCellValue(dataCell);
                    //先判断模型
                    boolean flag = convertLinkModelData(linkModelInfo, associationData, cellValue, headValue);
                    if(flag){
                        continue;
                    }
                    //根据表头和值设置数据
                    setLinkProperties(MwNetWorkLinkImportDto.class, linkImportDto, cellValue, headValue);
                }
            }
            linkImportDto.setAssociationData(associationData);
            linkImportDtos.add(linkImportDto);
        }
        return linkImportDtos;
    }

    private boolean convertLinkModelData( List<ModelPropertyParam> linkModelInfo,List<LinkLabelDto> associationData, Object dataValue, String headValue){
        if(CollectionUtils.isEmpty(linkModelInfo) || dataValue == null){return false;}
        LinkLabelDto linkLabelDto = null;
        for (ModelPropertyParam modelPropertyParam : linkModelInfo) {
            if(!modelPropertyParam.getName().equals(headValue)){continue;}
            linkLabelDto = new LinkLabelDto();
            linkLabelDto.setId(modelPropertyParam.getId());
            if(dataValue instanceof Double || dataValue instanceof Integer){
                linkLabelDto.setData(new BigDecimal(String.valueOf(dataValue)).setScale(0,BigDecimal.ROUND_HALF_UP).toString());
            }else{
                linkLabelDto.setData(String.valueOf(dataValue));
            }
            linkLabelDto.setLabel(modelPropertyParam.getName());
            PropertyTypeRef propertyTypeRef = modelPropertyParam.getPropertyTypeRef();
            if(propertyTypeRef.getTypeId().equals(PropertyTypeEnumSingle.ID)){
                Map<String, Object> context = propertyTypeRef.getContext();
                List<String> enumInfoList = (List<String>) context.get(enumInfoListKey);
                linkLabelDto.setEnumInfoList(enumInfoList);
            }
            linkLabelDto.setPropertyTypeId(propertyTypeRef.getTypeId());
        }
        if(linkLabelDto != null){
            associationData.add(linkLabelDto);
            return true;
        }
        return false;
    }


    private void setLinkProperties(Class cls, Object obj, Object dataValue, String headValue) throws Exception {
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            if (!field.isAnnotationPresent(ExcelProperty.class)) {
                continue;
            }
            ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
            String annotationValue = fieldAnnotation.value()[0];
            if (!annotationValue.equals(headValue)) {
                continue;
            }
            field.setAccessible(true);
            field.set(obj, dataValue);
        }
    }


    private void exportData(HttpServletResponse response,MwLinkTreeMapper linkTreeMapper,CmdbServiceManage cmdbServiceManage,List<MwNetWorkLinkImportDto> errorDtos,boolean isError) throws Exception {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet(SHEET_NAME);
        XSSFCellStyle headStyle = setHeadStyle(workbook);
        Row headerRow = sheet.createRow(0);
        //获取表头数据
        List<String> headInfo = getExportHeadInfo(cmdbServiceManage,100);
        if(isError){
            headInfo.add("导入结果");
            headInfo.add("错误信息");
        }
        for (int i = 0; i < headInfo.size(); i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headInfo.get(i));
            sheet.setColumnWidth(i, 6000);
            cell.setCellStyle(headStyle);
            linkGroupDropDown(linkTreeMapper,i,sheet,headInfo.get(i));
            takeValuePortDropDown(i,sheet,headInfo.get(i));
            enableDetectionDropDown(i,sheet,headInfo.get(i));
            detectionWayDropDown(i,sheet,headInfo.get(i));
        }
        List<Map<String, Object>> errorData = getErrorData(errorDtos);
        //写入数据
        int row = 1;
        for (Map<String, Object> errorDatum : errorData) {
            Row dataRow = sheet.createRow(row);
            for (int i = 0; i < headInfo.size(); i++){
                Cell cell = dataRow.createCell(i);
                Object value = errorDatum.get(headInfo.get(i));
                if(value != null){
                    cell.setCellValue(String.valueOf(value));
                }
            }
            row++;
        }
        Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        String fileName = milliSecond + ".xlsx";
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        OutputStream outputStream = response.getOutputStream();
        workbook.write(outputStream);
        workbook.close();
        outputStream.close();
    }


    private List<Map<String,Object>> getErrorData(List<MwNetWorkLinkImportDto> errorDtos) throws Exception {
        List<Map<String,Object>> realData = new ArrayList<>();
        for (MwNetWorkLinkImportDto errorDto : errorDtos) {
            Map<String,Object> dataMap = new HashMap<>();
            Field[] fields = errorDto.getClass().getDeclaredFields();
            for (Field field : fields) {
                if (!field.isAnnotationPresent(ExcelProperty.class)) {
                    continue;
                }
                ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
                String annotationValue = fieldAnnotation.value()[0];
                field.setAccessible(true);
                Object value = field.get(errorDto);
                dataMap.put(annotationValue,value);
            }
            List<LinkLabelDto> associationData = errorDto.getAssociationData();
            if(CollectionUtils.isNotEmpty(associationData)){
                for (LinkLabelDto associationDatum : associationData) {
                    if(associationDatum.getLabel().contains("["+MwNetWorkLinkConstant.LINK_NAME+"]")){
                        associationDatum.setLabel(associationDatum.getLabel().split("\\["+MwNetWorkLinkConstant.LINK_NAME)[0].trim());
                    }
                    dataMap.put(associationDatum.getLabel(),associationDatum.getData());
                }
            }
            realData.add(dataMap);
        }
        return realData;
    }

    private List<MwNetWorkLinkImportDto> importDataErrorMatch(MwNetWorkLinkDto netWorkLinkDto,List<MwNetWorkLinkImportDto> linkImportDtos){
        List<MwNetWorkLinkImportDto> importDtos = linkImportDtos.stream().filter(item -> item.getLinkName().equals(netWorkLinkDto.getLinkName())).collect(Collectors.toList());
        return importDtos;
    }

    private Object getCellValue(Cell cell) {
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                return cell.getNumericCellValue();
            default:
                return null;
        }
    }

    private String getOrgName(List<List<Long>> orgs,Map<Long,String> orgMap){
        String nameData = "";
        if(CollectionUtils.isNotEmpty(orgs)){
            for (List<Long> org : orgs) {
                StringBuilder orgName = new StringBuilder();
                for (Long aLong : org) {
                    String name = orgMap.get(aLong);
                    if(StringUtils.isEmpty(name)){
                        continue;
                    }
                    orgName.append(name+"/");
                }
                if(orgName != null && orgName.length() > 0){
                    orgName.deleteCharAt(orgName.length()-1);
                    if(StringUtils.isEmpty(nameData)){
                        nameData = orgName.toString();
                    }else{
                        nameData = nameData+","+orgName.toString();
                    }
                }
            }
        }
        return nameData;
    }

    private String getUserName(List<Long> users,Map<Long,String> userMap){
        String userName = "";
        if(CollectionUtils.isNotEmpty(users)){
            for (Long user : users) {
                String name = userMap.get(user);
                if(StringUtils.isEmpty(name)){
                    continue;
                }
                if(StringUtils.isEmpty(userName)){
                    userName = name;
                }else{
                    userName = userName + "," +name;
                }
            }
        }
        return userName;
    }

    private String getGroupName(List<Long> groups,Map<Long,String> groupMap){
        String groupName = "";
        if(CollectionUtils.isNotEmpty(groups)){
            for (Long group : groups) {
                String name = groupMap.get(group);
                if(StringUtils.isEmpty(name)){
                    continue;
                }
                if(StringUtils.isEmpty(groupName)){
                    groupName = name;
                }else{
                    groupName = groupName + "," +name;
                }
            }
        }
        return groupName;
    }
}
